<template>
  <div class="tableWrap" ref="tableWrap">
    <el-table
      v-loading="tableLoading"
      ref="tableList"
      :data="tableList"
      :height="(tableHeight && tableHeight + 'px') || undefined"
      :max-height="(tableHeight && tableHeight + 'px') || undefined"
      :show-summary="hasSummary"
      :summary-method="handleSummaryAction"
      :border="true"
      stripe
      :cell-style="tableCellStyle"
      :header-cell-style="{ background: '#e2e6e9', color: '#28221f' }"
      v-on="$listeners"
      v-bind="$attrs"
    >
      <!-- 多选栏插槽   -->
      <slot name="hasSelect"></slot>
      <!-- 序号栏插槽 -->
      <slot name="hasSort"></slot>
      <el-table-column
        v-for="(dataItem, dataIndex) in tableListMap"
        :key="dataIndex"
        :prop="dataItem.prop"
        :label="dataItem.label"
        :width="dataItem.width + 'px'"
        :align="dataItem.align || 'center'"
        :sortable="dataItem.sortable"
        :header-align="dataItem.align || 'center'"
        :show-overflow-tooltip="dataItem.tooltip"
        :fixed="dataItem.fixed"
      >
        <template slot="header">
          <div>
            {{ dataItem.label }}
            <el-popover v-if="dataItem.tooltipText" placement="top" trigger="hover">
              <span>{{ dataItem.tooltipText }}</span>
              <i class="el-icon-question cursorLink" slot="reference"></i>
            </el-popover>
          </div>
        </template>
        <slot name="tableHeader"></slot>
        <template slot-scope="scope">
          <template v-if="dataItem.type === 'input'">
            <el-input
              v-model="scope.row[dataItem.prop]"
              :disabled="dataItem.disabled"
              :readonly="dataItem.readonly"
              :placeholder="dataItem.placeholder || ''"
            ></el-input>
          </template>
          <template v-else-if="dataItem.type === 'select'">
            <el-select
              v-model="scope.row[dataItem.prop]"
              :placeholder="dataItem.placeholder || ''"
              :disabled="dataItem.disabled"
              :readonly="dataItem.readonly"
              :filterable="dataItem.filterable"
              :clearable="dataItem.clearable"
              @change="changeSelectAction($event, scope, dataItem)"
            >
              <el-option
                v-for="(optionItem, optionIndex) in optionListMap[dataItem.prop]"
                :key="optionIndex"
                :label="optionItem[dataItem.optionLabel || dataItem.optionLabelText || 'label']"
                :value="optionItem[dataItem.optionValue || 'value']"
              ></el-option>
            </el-select>
          </template>
          <template v-else-if="dataItem.type === 'image'">
            <el-image :src="scope.row[dataItem.prop]"></el-image>
          </template>
          <template v-else-if="dataItem.type === 'date-text'">{{ handleDataDate(scope.row[dataItem.prop], dataItem.format) }}</template>
          <template v-else-if="dataItem.type === 'money-text'">{{ setFormatNumber(scope.row[dataItem.prop], dataItem.unit, dataItem.fixedNum) }}</template>
          <template v-else-if="dataItem.type === 'linkText'">
            <div
              class="underline cursorLink"
              @click="
                dataItem.customClick &&
                  dataItem.customClick(dataItem.prop, dataItem.action, {
                    _this: currentInstance,
                    scopeItem: scope.row,
                  })
              "
            >
              {{ (dataItem.customFormat && dataItem.customFormat(dataItem.prop, scope.row[dataItem.prop])) || scope.row[dataItem.prop] }}
            </div>
          </template>
          <!-- 需要匹配的label(通常通过value来匹配对应的label值) -->
          <template v-else-if="dataItem.optionKey">{{ getTableLabel(dataItem.optionKey, scope.row[dataItem.prop], dataItem.option) }}</template>
          <template v-else>
            {{ (dataItem.customFormat && dataItem.customFormat(dataItem.prop, scope.row[dataItem.prop])) || scope.row[dataItem.prop] }}
          </template>
        </template>
        <el-table-column
          v-for="(secondItem, secondIndex) in dataItem.children"
          :key="secondIndex"
          :prop="secondItem.prop"
          :label="secondItem.label"
          :width="secondItem.width + 'px'"
          :align="secondItem.align || 'center'"
          :sortable="secondItem.sort"
          :header-align="secondItem.align || 'center'"
          :show-overflow-tooltip="secondItem.tooltip"
          :fixed="secondItem.fixed"
        >
          <slot name="childTableHeader"></slot>
          <template slot-scope="scope">
            <template v-if="secondItem.type === 'input'">
              <el-input
                v-model="scope.row[secondItem.prop]"
                :disabled="secondItem.disabled"
                :readonly="secondItem.readonly"
                :placeholder="secondItem.placeholder || ''"
              ></el-input>
            </template>
            <template v-else-if="secondItem.type === 'select'">
              <el-select
                v-model="scope.row[secondItem.prop]"
                :placeholder="secondItem.placeholder || ''"
                :disabled="secondItem.disabled"
                :readonly="secondItem.readonly"
              >
                <el-option
                  v-for="(optionItem, optionIndex) in optionListMap[secondItem.prop]"
                  :key="optionIndex"
                  :label="optionItem[secondItem.optionLabel || secondItem.optionLabelText || 'label']"
                  :value="optionItem[secondItem.optionValue || 'value']"
                ></el-option>
              </el-select>
            </template>
            <template v-else-if="secondItem.type === 'image'">
              <el-image :src="scope.row[secondItem.prop]"></el-image>
            </template>
            <template v-else-if="secondItem.type === 'date-text'">{{ handleDataDate(scope.row[secondItem.prop], secondItem.format) }}</template>
            <template v-else-if="secondItem.type === 'money-text'">
              {{ setFormatNumber(scope.row[secondItem.prop], secondItem.unit, secondItem.fixedNum) }}
            </template>
            <template v-else-if="secondItem.type === 'linkText'">
              <div
                class="underline cursorLink"
                @click="
                  secondItem.customClick &&
                    secondItem.customClick(secondItem.prop, secondItem.action, {
                      __this: currentInstance,
                      scopeItem: scope.row,
                    })
                "
              >
                {{ (secondItem.customFormat && secondItem.customFormat(secondItem.prop, scope.row[secondItem.prop])) || scope.row[secondItem.prop] }}
              </div>
            </template>
            <template v-else-if="secondItem.optionKey">{{ getTableLabel(secondItem.optionKey, scope.row[secondItem.prop], secondItem.option) }}</template>
            <template v-else>
              {{ (secondItem.customFormat && secondItem.customFormat(secondItem.prop, scope.row[secondItem.prop])) || scope.row[secondItem.prop] }}
            </template>
          </template>
        </el-table-column>
      </el-table-column>
      <!-- 操作栏插槽 -->
      <slot name="hasHandle"></slot>
    </el-table>
    <div v-if="hasPagination && tableTotal > 0" :class="hasCustomPageStyle ? 'paginationStyle' : 'paginationContainer'">
      <el-pagination
        background
        :current-page.sync="pagination.pageNum"
        :page-sizes="[10, 20, 50, 100]"
        :page-size="pagination.pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="tableTotal"
        @size-change="handlePageSize"
        @current-change="init"
      ></el-pagination>
    </div>
  </div>
</template>
<script>
import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
import pickBy from 'lodash/pickBy';
import { getTableListAction } from '@/api';
import { setTreeRowKey } from '@/utils';
import { getTableLabel } from '@/static/js/dataSource';
// import getTableHeight from "@/static/mixin/getTableHeight";
import setEditForm from '@/static/mixin/setEditForm';
export default {
  name: 'TableList',
  inheritAttrs: false,
  // mixins: [getTableHeight],
  mixins: [setEditForm],
  props: {
    isTree: {
      type: Boolean,
      default: false,
    },
    treechildName: {
      type: String,
      default: 'children',
    },
    // 是否需要合计行
    hasSummary: {
      type: Boolean,
      default: false,
    },
    // 是否需要序号栏
    hasSort: {
      type: Boolean,
      default: true,
    },
    // 列表是否需要分页
    hasPagination: {
      type: Boolean,
      default: true,
    },
    // 是否需要自定义分页样式
    hasCustomPageStyle: {
      type: Boolean,
      default: false,
    },
    // 是否需要动态计算表格高度
    hasDynamicTable: {
      type: Boolean,
      default: false,
    },
    tableHeight: {
      type: Number,
      default: 0,
    },
    tableDataList: {
      type: Array,
      default: function () {
        return null;
      },
    },
    // 请求表格所需的axios参数
    request: {
      type: Object,
      default: function () {
        return {};
      },
    },
  },
  watch: {
    tableList: {
      handler(val) {
        this.handleEventAction('changeTableListAction', val);
      },
      deep: true,
    },
  },
  data() {
    return {
      currentInstance: this,
      tableList: [],
      tableLoading: false,
      tableTotal: 0,
      pagination: {
        pageNum: 1,
        pageSize: 20,
      },
    };
  },
  methods: {
    init() {
      this.getDataList();
      this.$nextTick(() => {
        this.$refs?.tableList?.doLayout();
      });
    },
    tableCellStyle({ row, column, rowIndex, columnIndex }) {
      let customCellStyle = {};
      this.tableListMap.map((item) => {
        if (item.customCellStyle && column.property === item.prop) {
          customCellStyle = item.customCellStyle({ row, column, rowIndex, columnIndex });
        }
      });
      return customCellStyle;
    },
    handlePageSize(pageSize) {
      this.pagination.pageSize = pageSize;
      this.getDataList();
    },
    // 所有下拉组件的全局事件
    changeSelectAction(value, scope, dataItem) {
      this.handleEventAction('changeAction', ...{ scopeItem: scope.row, index: scope.$index, prop: dataItem.prop, dataItem });
    },
    getDataList() {
      if (this.tableDataList) {
        this.tableList = cloneDeep(this.tableDataList);
        return;
      }
      // 过滤对象里的空参数
      const pageParam = this.hasPagination ? pickBy({ ...this.pagination }) : {};
      this.tableLoading = true;
      const { apiKey, params, method } = this.request;
      getTableListAction({
        apiKey,
        params: Object.assign({}, params, pageParam),
        method,
      }).then((res) => {
        this.tableLoading = false;
        if (this.hasPagination) {
          this.tableTotal = (res && res.total) || 0;
          this.tableList = (res && res.rows) || [];
        } else {
          this.tableList = (res && res.data) || [];
        }
        if (this.isTree) {
          this.tableList = setTreeRowKey(res.rows, this.treechildName);
        }
        this.$nextTick(() => {
          this.$refs?.tableList?.doLayout();
        });
      });
    },
    handleSummaryAction(param) {
      const { columns, data } = param;
      const sums = [];
      // 需要合计统计的表格字段
      const handleTableMap = getChildrenItem(this.tableListMap);
      const showSummaryMap = handleTableMap.filter((item) => !item.showSummary);
      const showSummaryArr = showSummaryMap.map((item) => item.prop);
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = '合计';
          return;
        }
        if (showSummaryArr.includes(column.property)) return;
        const columnItemMap = handleTableMap?.find((item) => item.prop === column.property) || {};
        const values = data.map((item) => Number(item[column.property]));
        if (!values.every((value) => isNaN(value))) {
          sums[index] = values.reduce((prev, curr, index) => {
            const handlePrev = this.setFormatNumber(prev || 0, 'float', columnItemMap.fixedNum);
            const handleCurr = this.setFormatNumber(curr || 0, 'float', columnItemMap.fixedNum);
            const handleTotal = this.setFormatNumber(prev + curr || 0, columnItemMap.unit, columnItemMap.fixedNum);
            // 最后总数按原定格式显示
            if (index === values.length - 1) {
              return handleTotal;
            }
            const value = Number(curr);
            if (!isNaN(value)) {
              return Number(handlePrev) + Number(handleCurr);
            } else {
              return handlePrev;
            }
          }, 0);
        } else {
          sums[index] = '';
        }
      });
      this.$nextTick(() => {
        this.$refs.tableList.doLayout();
      });
      function getChildrenItem(children) {
        let childrenItem = [];
        children.map((item) => {
          if (item?.children?.length) {
            childrenItem = childrenItem.concat(getChildrenItem(item.children));
          } else {
            childrenItem.push(item);
          }
        });
        return childrenItem;
      }
      return sums;
    },
    getTableLabel(optionKey, value, option = {}) {
      return getTableLabel(optionKey, value, option);
    },
    handleDataDate(dataStr, format) {
      return dataStr && moment(dataStr).format(format);
    },
    setFormatNumber(num, unit = 'money', fixedNum = 2) {
      const reg = /\d{1,3}(?=(\d{3})+$)/g;
      const unitMap = {
        integer: parseInt(num),
        float: parseFloat(num).toFixed(fixedNum),
        money: (parseFloat(num).toFixed(fixedNum) + '').replace(reg, '$&,'),
        percent: (num * 100).toFixed(fixedNum),
      };
      return unitMap[unit] === '-0' ? '0' : unitMap[unit];
    },
    handleEventAction(eventName, params) {
      this.$emit(eventName, params);
    },
  },
};
</script>
<style lang="scss" scoped>
.tableWrap {
  position: relative;
  // 保留文本中的换行符
  & ::v-deep .el-table th.el-table__cell > .cell {
    white-space: pre-wrap;
  }
  & ::v-deep .el-image .el-image__inner {
    display: inline-block;
    width: 50px;
    height: 50px;
  }
  .paginationStyle {
    margin-top: 15px;
    background-color: #fff;
    text-align: right;
  }
  .underline {
    text-decoration: underline;
  }
  .cursorLink:hover {
    cursor: pointer;
  }
}
.paginationContainer {
  margin-top: 15px;
  text-align: right;
}
</style>
